package com.yeyks.mattress.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.yeyks.common.em.mattress.MattressPayRecordStatusEnum;
import com.yeyks.common.em.mattress.OrderInfoMattressOrderTypeEnum;
import com.yeyks.common.em.mattress.OrderInfoMattressPayTypeEnum;
import com.yeyks.common.em.mattress.OrderInfoMattressStatusEnum;
import com.yeyks.common.em.pay.PayTypeEnum;
import com.yeyks.common.utils.ArgumentsCheckUtil;
import com.yeyks.common.utils.IdWorkerUtil;
import com.yeyks.common.utils.TryCatchUtil;
import com.yeyks.commonReference.append.mattress.api.MattressApiCallService;
import com.yeyks.commonReference.append.mattress.api.MattressApiCallServiceBaseVo;
import com.yeyks.commonReference.append.mattress.mongodb.entity.MattressPayCallbackFailRecordMongoEntity;
import com.yeyks.commonReference.append.mattress.mongodb.entity.MattressPayCallbackRecordMongoEntity;
import com.yeyks.commonReference.append.mattress.mongodb.repository.MattressPayCallbackFailRecordMongoRepository;
import com.yeyks.commonReference.append.mattress.mongodb.service.MattressPayCallbackRecordMongoService;
import com.yeyks.commonReference.append.mattress.wechat.config.MattressWxConfigUtil;
import com.yeyks.commonReference.append.mattress.wechat.config.MattressWxProperties;
import com.yeyks.commonReference.service.mattress.OrderInfoMattressService;
import com.yeyks.commonReference.utils.PayUtil;
import com.yeyks.mattress.dal.domain.MattressPayRecord;
import com.yeyks.mattress.dal.domain.OrderInfoMattress;
import com.yeyks.mattress.service.MattressPayRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Api(tags = "微信", description = "微信")
@Controller
@RequestMapping("/mattress/wechat")
@Slf4j
public class WechatContrller {

    @Autowired
    private MattressWxConfigUtil mattressWxConfigUtil;
    @Autowired
    private MattressWxProperties mattressWxProperties;
    @Autowired
    private MattressPayCallbackRecordMongoService mattressPayCallbackRecordMongoService;
    @Autowired
    private MattressPayCallbackFailRecordMongoRepository mattressPayCallbackFailRecordMongoRepository;
    @Autowired
    private OrderInfoMattressService orderInfoMattressService;
    @Autowired
    private MattressPayRecordService mattressPayRecordService;
    @Autowired(required = false)
    private MattressApiCallService mattressApiCallService;

    private ExecutorService executorService = Executors.newFixedThreadPool(20);

    @ApiOperation(value = "微信授权:v1.0.0")
    @CrossOrigin
    @GetMapping("/authorize")
    public String authorize(@RequestParam(name = "returnUrl") String returnUrl, @RequestParam(name = "type", defaultValue = "gzh") String type) {
        if (returnUrl != null) {
            returnUrl = URLEncoder.encode(returnUrl);
        }
        String baseUrl = mattressWxConfigUtil.getMattressWxMpService().oauth2buildAuthorizationUrl(
                mattressWxProperties.getRedirectUrl(),
                WxConsts.OAuth2Scope.SNSAPI_BASE,
                returnUrl);
        log.info("baseUrl打印：{}", baseUrl);
        return "redirect:" + baseUrl;
    }

    @ApiOperation(value = "微信授权回调:v1.0.0")
    @ApiIgnore
    @RequestMapping("/callback")
    public String callback(String code, String state) {
        WxMpOAuth2AccessToken accessToken = new WxMpOAuth2AccessToken();
        try {
            accessToken = mattressWxConfigUtil.getMattressWxMpService().oauth2getAccessToken(code);
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        String openId = accessToken.getOpenId();
        log.info("授权成功：" + openId);
        if (ArgumentsCheckUtil.notEmpty(state) && state.contains("?")) {
            return "redirect:" + state + "&openId=" + openId;
        } else {
            return "redirect:" + state + "?openId=" + openId;
        }
    }

    @ApiOperation(value = "微信支付回调:v1.0.0")
    @ApiIgnore
    @RequestMapping("/payCallback")
    @ResponseBody
    public String payCallback(HttpServletRequest request) {
        try {
            String xmlStr = IOUtils.toString(request.getInputStream(), "utf-8");
            log.info("xmlStr = {}", xmlStr);
            WxPayOrderNotifyResult resultCode = mattressWxConfigUtil.getMattressGzhWxPayService().parseOrderNotifyResult(xmlStr);
            TryCatchUtil.tryCatch(() -> {
                mattressPayCallbackRecordMongoService.save(new MattressPayCallbackRecordMongoEntity()
                        .setId(IdWorkerUtil.nextStrId())
                        .setCreateDate(new Date())
                        .setType(PayTypeEnum.WXPAY.desc())
                        .setRequestMessage(xmlStr)
                        .setText(JSONUtil.toJsonStr(resultCode)));
            });
            if (resultCode == null) {
                return WxPayNotifyResponse.fail("返回结果为空");
            }
            // 另起线程处理业务
            executorService.execute(() -> dealWork(resultCode));
            return WxPayNotifyResponse.success("处理成功!");
        } catch (Exception e) {
            log.error("微信支付回调结果异常,异常原因{}", e.getMessage());
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }

    //处理回调业务
    @Transactional(rollbackFor = Exception.class)
    private void dealWork(WxPayOrderNotifyResult wxPayOrderNotifyResult) {
        try {
            //获取附加信息
            String attach = wxPayOrderNotifyResult.getAttach();
            Map<String, String> attachMap = PayUtil.getAttach(attach);
            String orderType = attachMap.get("orderType");
            String payType = attachMap.get("payType");
            //支付状态
            boolean flag = false;
            if (wxPayOrderNotifyResult.getResultCode().equals("SUCCESS")) {
                flag = true;
            }
            //根据订单种类处理支付结果
            if (OrderInfoMattressOrderTypeEnum.MATTRESS.desc().equals(orderType)) {
                dealMattressOrder(flag, payType, wxPayOrderNotifyResult);
            }
        } catch (Exception e) {
            TryCatchUtil.tryCatch(() -> {
                mattressPayCallbackFailRecordMongoRepository.save(new MattressPayCallbackFailRecordMongoEntity()
                        .setId(IdWorkerUtil.nextStrId())
                        .setCreateDate(new Date())
                        .setText(wxPayOrderNotifyResult.getOutTradeNo()));
            });
            throw e;
        }
    }

    //处理床垫订单
    private void dealMattressOrder(boolean flag, String payType, WxPayOrderNotifyResult wxPayOrderNotifyResult) {
        Integer payTypeInt = OrderInfoMattressPayTypeEnum.getValue(payType);
        //处理订单号
        String orderNo = wxPayOrderNotifyResult.getOutTradeNo().substring(0, wxPayOrderNotifyResult.getOutTradeNo().indexOf(payType));
        //处理订单
        MattressPayRecord mattressPayRecord = mattressPayRecordService.getOne(new QueryWrapper<MattressPayRecord>()
                .eq(MattressPayRecord.ORDER_NO, orderNo)
                .eq(MattressPayRecord.PAY_TYPE, payTypeInt)
                .eq(MattressPayRecord.STATUS, MattressPayRecordStatusEnum.PAY_BEFORE.value()));
        if (null != mattressPayRecord) {
            Date date = new Date();
            //更新支付记录
            MattressPayRecord mattressPayRecordNew = new MattressPayRecord();
            mattressPayRecordNew.setId(mattressPayRecord.getId());
            if (flag) {
                mattressPayRecordNew.setStatus(MattressPayRecordStatusEnum.PAY_SUCCESS.value());
            } else {
                mattressPayRecordNew.setStatus(MattressPayRecordStatusEnum.PAY_FAIL.value());
            }
            mattressPayRecordNew.setPayReturnNo(wxPayOrderNotifyResult.getTransactionId());
            mattressPayRecordNew.setFinishTime(wxPayOrderNotifyResult.getTimeEnd());
            mattressPayRecordNew.setPayResult(JSONUtil.toJsonStr(wxPayOrderNotifyResult));
            mattressPayRecordNew.setUpdateTime(date);
            mattressPayRecordService.updateById(mattressPayRecordNew);
            //更新订单
            OrderInfoMattress orderInfoMattress = orderInfoMattressService.getOne(new QueryWrapper<OrderInfoMattress>()
                    .eq(OrderInfoMattress.ORDER_NO, orderNo));
            if (null != orderInfoMattress) {
                OrderInfoMattress orderInfoMattressNew = new OrderInfoMattress();
                orderInfoMattressNew.setId(orderInfoMattress.getId());
                orderInfoMattressNew.setPaymentMethod(payTypeInt);
                orderInfoMattressNew.setOverTime(DateUtil.offsetSecond(date, orderInfoMattress.getPackageTimeLong()));
                orderInfoMattressNew.setStatus(OrderInfoMattressStatusEnum.STARTUP_SUCCESSFUL.value());
                orderInfoMattressService.updateById(orderInfoMattressNew);
                if (flag) {
                    //v1.0.1
                    //添加机器锁(待使用),锁定时间延长30秒
//                    valueOperations.set(RedisKeyPreContent.MATTRESS_MECHANICAL_LOCK + orderInfoMattress.getImeiId(), "lock", orderInfoMattress.getPackageTimeLong() + 30, TimeUnit.SECONDS);
                    //运行机器
                    MattressApiCallServiceBaseVo mattressApiCallServiceBaseVo = null;
                    try {
                        mattressApiCallServiceBaseVo = mattressApiCallService.startUp(orderInfoMattress.getImeiId(), orderInfoMattress.getPackageTimeLong());
                    } catch (Exception e) {
                    }
                    if (null != mattressApiCallServiceBaseVo && mattressApiCallServiceBaseVo.getCode().equals(0)) {
                        //添加机器锁(正式)
                        //v1.0.1
//                        valueOperations.set(RedisKeyPreContent.MATTRESS_MECHANICAL_LOCK + orderInfoMattress.getImeiId(), "locked", orderInfoMattress.getPackageTimeLong(), TimeUnit.SECONDS);
                    } else {
                        log.error("床垫启动失败失败:payType:{},orderNo{},imeiId:{}", payType, orderNo, orderInfoMattress.getImeiId());
                        //去掉机器锁
                        //v1.0.1
//                        redisTemplate.delete(RedisKeyPreContent.MATTRESS_MECHANICAL_LOCK + orderInfoMattress.getImeiId());
                        dealStratupMattressFail(payType, orderNo);
                    }
                }
            }
        }
    }

    //开启床垫失败后的退款等操作
    private void dealStratupMattressFail(String payType, String orderNo) {
//        Integer payTypeInt = OrderInfoMattressPayTypeEnum.getValue(payType);
        OrderInfoMattress orderInfoMattress = orderInfoMattressService.getOne(new QueryWrapper<OrderInfoMattress>()
                .eq(OrderInfoMattress.ORDER_NO, orderNo));
        Integer snapshotTotalFee = orderInfoMattress.getSnapshotTotalFee();
        //退款
//        WxPayRefundResult wxPayRefundResult = null;
//        try {
//            MattressWechatPayServiceRefundParam mattressWechatPayServiceRefundParam = new MattressWechatPayServiceRefundParam();
//            mattressWechatPayServiceRefundParam.setPayType(payType);
//            mattressWechatPayServiceRefundParam.setOrderNo(orderNo);
//            mattressWechatPayServiceRefundParam.setTotalFee(snapshotTotalFee);
//            mattressWechatPayServiceRefundParam.setRefundFee(snapshotTotalFee);
//            wxPayRefundResult = mattressPayService.doRefund(mattressWechatPayServiceRefundParam);
//            if (null == wxPayRefundResult) {
//                log.error("床垫订单自动退款失败:payType:{},orderNo{}", payType, orderNo);
//            }
//        } catch (Exception e) {
//            log.error("床垫订单自动退款失败:payType:{},orderNo{}", payType, orderNo);
//        }
        //修改支付记录
//        MattressPayRecord mattressPayRecord = mattressPayRecordService.getOne(new QueryWrapper<MattressPayRecord>()
//                .eq(MattressPayRecord.ORDER_NO, orderNo)
//                .eq(MattressPayRecord.PAY_TYPE, payTypeInt));
//        MattressPayRecord mattressPayRecordNew = new MattressPayRecord();
//        mattressPayRecordNew.setId(mattressPayRecord.getId());
//        mattressPayRecordNew.setStatus(MattressPayRecordStatusEnum.REFUND.value());
//        mattressPayRecordNew.setRefundAmount(snapshotTotalFee);
//        mattressPayRecordNew.setRefundResult(null != wxPayRefundResult ? JSONUtil.toJsonStr(wxPayRefundResult) : null);
//        mattressPayRecordNew.setRefundTime(new Date());
//        boolean b = mattressPayRecordService.updateById(mattressPayRecordNew);
//        if (!b) {
//            log.error("床垫订单自动退款支付记录修改失败:mattressPayRecordNew:{}", JSONUtil.toJsonStr(mattressPayRecordNew));
//        }
        //修改订单
        OrderInfoMattress orderInfoMattressNew = new OrderInfoMattress();
        orderInfoMattressNew.setId(orderInfoMattress.getId());
        orderInfoMattressNew.setSnapshotRefundFee(snapshotTotalFee);
        orderInfoMattressNew.setStatus(OrderInfoMattressStatusEnum.STARTUP_FAILED.value());
        boolean b = orderInfoMattressService.updateById(orderInfoMattressNew);
        if (!b) {
            log.error("床垫订单自动退款订单记录修改失败:orderInfoMattress:{}", JSONUtil.toJsonStr(orderInfoMattress));
        }
    }

}
